package com.sunxd.zstudy.mybatise.domain.service.engine.handler.join;

import com.google.common.base.Throwables;
import com.sunxd.zstudy.mybatise.application.facade.request.interactive.base.BaseInteractiveJoinRequest;
import com.sunxd.zstudy.mybatise.application.facade.response.interactive.base.BaseInteractiveJoinDetailInfo;
import com.sunxd.zstudy.mybatise.domain.cache.InteractiveActivityCache;
import com.sunxd.zstudy.mybatise.domain.contans.consts.InteractiveErrorCode;
import com.sunxd.zstudy.mybatise.domain.contans.enums.InteractiveStatusEnum;
import com.sunxd.zstudy.mybatise.domain.dto.DeductionTicketParam;
import com.sunxd.zstudy.mybatise.domain.dto.InteractiveActivity;
import com.sunxd.zstudy.mybatise.domain.exception.InternalServerException;
import com.sunxd.zstudy.mybatise.domain.service.context.InteractiveContextInfo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

/**
 * Description: 抽象活动参与处理器
 */
@Slf4j
@Component
public abstract class BaseInteractiveJoinHandler<T extends BaseInteractiveJoinRequest, R extends BaseInteractiveJoinDetailInfo<?>>
        implements InteractiveJoinHandler<T, R> {


    /**
     * do common business logic
     * 1. risk control
     * 2. pre handle
     * 3. build context
     * 4. run join with context
     *
     * @param request 参与活动请求
     * @return 参与活动响应
     */
    @Override
    public R join(@NonNull T request) throws ExecutionException {
        InteractiveActivity interactiveActivity = new InteractiveActivity();
        Optional<InteractiveActivity> activityOptional = Optional.ofNullable(InteractiveActivityCache.cache.get(request.getActivityCode()));
        if (!activityOptional.isPresent()) {
            throw new InternalServerException(InteractiveErrorCode.INTERACTIVE_NOT_EXIST);
        }
        // 活动时间、状态校验
        interactiveActivity = activityOptional.get();
        checkCampaignTimeAndStatus(interactiveActivity);
        String userId = request.getPassengerUuid();

        InteractiveContextInfo interactiveContextInfo = new InteractiveContextInfo();
        interactiveContextInfo.setInteractiveActivity(interactiveActivity);
        // 构造风控参数
        // 白名单--跳过群组、标签认证
        // 1. 门槛风控校验
        // 2. 安全性风控校验

        // 记录当前使用的次数是免费还是赠送
        DeductionTicketParam deductionTicketParam = null;
        try {
            //2. pre handle 扣减免费参与次数/活动次数
//            deductionTicketParam = preHandler.preHandler(request, capability);
//            capabilityContext.setDeductionTicketParam(deductionTicketParam);
            // 4. 活动执行
            R joinData = join(request, interactiveContextInfo);
            //异步调用打标接口
            // 异步记录参与活动 & 活动热度
//            asyncCampaignParticipated.record(request.getUserId(), capability);
            //异步记录活动使用次数
//            preHandler.recordTicket(deductionTicketParam);
            return joinData;

        } catch (Exception e) {
            // 回退风控信息
            //回退活动次数
            log.error(Throwables.getStackTraceAsString(e));
            throw new InternalServerException(InteractiveErrorCode.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 模版方法，带上下文的join实现
     *
     * @param request 参加请求
     * @param context 上下文参数
     * @return 参与活动响应
     */
    protected abstract @Nullable R join(T request, InteractiveContextInfo context);



    /**
     * 风控判断
     *
     * @param riskRes 风控返回结果
     */



    /**
     * 判断活动时间
     */
    private void checkCampaignTimeAndStatus(InteractiveActivity activityPO) {
        Date now = new Date();
        if (now.before(activityPO.getBeginTime())
                || activityPO.getActivityStatus().equals(InteractiveStatusEnum.DRAFT.getValue())
                || activityPO.getActivityStatus().equals(InteractiveStatusEnum.NOT_STARTED.getValue())) {
            throw new InternalServerException(InteractiveErrorCode.INTERACTIVE_NOT_START);
        }
        if (now.after(activityPO.getEndTime())
                || activityPO.getActivityStatus().equals(InteractiveStatusEnum.ALREADY_STOP_STATUS.getValue())) {
            throw new InternalServerException(InteractiveErrorCode.INTERACTIVE_END);
        }
    }


}
